#include "Property.h"
#include "Util.h"
#include <stdlib.h>
#include <memory.h>

namespace amqp {

    void ReleaseProperty(amqp_basic_properties_t& prop) {
        ReleaseBytes(prop.content_type);
        ReleaseBytes(prop.content_encoding);
        ReleaseBytes(prop.correlation_id);
        ReleaseBytes(prop.reply_to);
        ReleaseBytes(prop.expiration);
        ReleaseBytes(prop.message_id);
        ReleaseBytes(prop.type);
        ReleaseBytes(prop.user_id);
        ReleaseBytes(prop.app_id);
        ReleaseBytes(prop.cluster_id);
        memset(&prop, 0x00, sizeof(prop));
    }

    void ReleaseTable(amqp_table_t& tb) {
        //amqp_table_clone();
    }

    void CopyProperty(amqp_basic_properties_t& to, const amqp_basic_properties_t& from, amqp_pool_t& pool) {

        if (from._flags & AMQP_BASIC_CONTENT_TYPE_FLAG) {
            CopyBytes(to.content_type, from.content_type);
        }
        if (from._flags & AMQP_BASIC_CONTENT_ENCODING_FLAG) {
            CopyBytes(to.content_encoding, from.content_encoding);
        }
        if (from._flags & AMQP_BASIC_CORRELATION_ID_FLAG) {
            CopyBytes(to.correlation_id, from.correlation_id);
        }
        if (from._flags & AMQP_BASIC_REPLY_TO_FLAG) {
            CopyBytes(to.reply_to, from.reply_to);
        }
        if (from._flags & AMQP_BASIC_EXPIRATION_FLAG) {
            CopyBytes(to.expiration, from.expiration);
        }
        if (from._flags & AMQP_BASIC_MESSAGE_ID_FLAG) {
            CopyBytes(to.message_id, from.message_id);
        }
        if (from._flags & AMQP_BASIC_TYPE_FLAG) {
            CopyBytes(to.type, from.type);
        }
        if (from._flags & AMQP_BASIC_USER_ID_FLAG) {
            CopyBytes(to.user_id, from.user_id);
        }
        if (from._flags & AMQP_BASIC_APP_ID_FLAG) {
            CopyBytes(to.app_id, from.app_id);
        }
        if (from._flags & AMQP_BASIC_CLUSTER_ID_FLAG) {
            CopyBytes(to.cluster_id, from.cluster_id);
        }
        if (from._flags & AMQP_BASIC_DELIVERY_MODE_FLAG) {
            to.delivery_mode = from.delivery_mode;
        }
        if (from._flags & AMQP_BASIC_PRIORITY_FLAG) {
            to.priority = from.priority;
        }
        if (from._flags & AMQP_BASIC_TIMESTAMP_FLAG) {
            to.timestamp = from.timestamp;
        }

        if (from._flags & AMQP_BASIC_HEADERS_FLAG) {
            amqp_table_clone(&from.headers, &to.headers, &pool);
        }

        to._flags = from._flags;
    }

    Property::Property() {
        memset(&m_prop, 0x00, sizeof(amqp_basic_properties_t));
        init_amqp_pool(&m_pool, 128);
    }

    Property::Property(const amqp_basic_properties_t& prop): Property() {
        CopyProperty(m_prop, prop, m_pool);
    }

    Property::~Property() {
        ReleaseProperty(m_prop);
        empty_amqp_pool(&m_pool);
    }

    Property& Property::operator=(Property & src) {
        return *this;
    }

    const amqp_basic_properties_t* Property::getProperties()const { return &m_prop; }

    void Property::CopyFrom(const amqp_basic_properties_t* prop) {
        CopyProperty(m_prop, *prop, m_pool);
    }

    std::string  Property::ContentType() const {
        return bytes_to_string(m_prop.content_type);
    }

    void  Property::ContentType(const std::string & content_type) {
        SetBytes(m_prop.content_type, content_type);
        m_prop._flags |= AMQP_BASIC_CONTENT_TYPE_FLAG;
    }

    std::string  Property::ContentEncoding() const {
        return bytes_to_string(m_prop.content_encoding);
    }

    void  Property::ContentEncoding(const std::string & content_encoding) {
        SetBytes(m_prop.content_encoding, content_encoding);
        m_prop._flags |= AMQP_BASIC_CONTENT_ENCODING_FLAG;
    }

    delivery_mode_t  Property::DeliveryMode() const {
        return (delivery_mode_t)m_prop.delivery_mode;
    }

    void  Property::DeliveryMode(delivery_mode_t delivery_mode) {
        m_prop.delivery_mode = static_cast<uint8_t>(delivery_mode);
        m_prop._flags |= AMQP_BASIC_DELIVERY_MODE_FLAG;
    }

    uint8_t  Property::Priority() const {
        return m_prop.priority;
    }
    void  Property::Priority(uint8_t priority) {
        m_prop.priority = priority;
        m_prop._flags |= AMQP_BASIC_PRIORITY_FLAG;
    }

    std::string  Property::CorrelationId() const {
        return bytes_to_string(m_prop.correlation_id);
    }

    void  Property::CorrelationId(const std::string & correlation_id) {
        SetBytes(m_prop.correlation_id, correlation_id);
        m_prop._flags |= AMQP_BASIC_CORRELATION_ID_FLAG;
    }

    std::string  Property::ReplyTo() const {
        return  bytes_to_string(m_prop.reply_to);
    }

    void  Property::ReplyTo(const std::string & reply_to) {
        SetBytes(m_prop.reply_to, reply_to);
        m_prop._flags |= AMQP_BASIC_REPLY_TO_FLAG;
    }

    std::string  Property::Expiration() const {
        return bytes_to_string(m_prop.expiration);
    }
    void  Property::Expiration(const std::string & expiration) {
        SetBytes(m_prop.expiration, expiration);
        m_prop._flags |= AMQP_BASIC_EXPIRATION_FLAG;
    }

    std::string  Property::MessageId() const {
        return bytes_to_string(m_prop.message_id);
    }
    void  Property::MessageId(const std::string & message_id) {
        SetBytes(m_prop.message_id, message_id);
        m_prop._flags |= AMQP_BASIC_MESSAGE_ID_FLAG;
    }

    uint64_t  Property::Timestamp() const {
        return m_prop.timestamp;
    }
    void  Property::Timestamp(uint64_t timestamp) {
        m_prop.timestamp = timestamp;
        m_prop._flags |= AMQP_BASIC_TIMESTAMP_FLAG;
    }

    std::string  Property::Type() const {
        return bytes_to_string(m_prop.type);
    }
    void  Property::Type(const std::string & type) {
        SetBytes(m_prop.type, type);
        m_prop._flags |= AMQP_BASIC_TYPE_FLAG;
    }

    std::string  Property::UserId() const {
        return  bytes_to_string(m_prop.user_id);
    }

    void  Property::UserId(const std::string & user_id) {
        SetBytes(m_prop.user_id, user_id);
        m_prop._flags |= AMQP_BASIC_USER_ID_FLAG;
    }

    std::string  Property::AppId() const {
        return bytes_to_string(m_prop.app_id);
    }

    void  Property::AppId(const std::string & app_id) {
        SetBytes(m_prop.app_id, app_id);
        m_prop._flags |= AMQP_BASIC_APP_ID_FLAG;
    }

    std::string  Property::ClusterId() const {
        return bytes_to_string(m_prop.app_id);
    }

    void  Property::ClusterId(const std::string & cluster_id) {
        SetBytes(m_prop.cluster_id, cluster_id);
        m_prop._flags |= AMQP_BASIC_CLUSTER_ID_FLAG;
    }
}
